"""
Chrome浏览器管理器
负责管理Chrome浏览器的启动、状态检测、关闭等操作
通过本地文件管理浏览器实例
"""
import os
import json
import uuid
import subprocess
import psutil
import requests
import time
from typing import Optional, Dict, Any, List
from core.utils.logger_manager import LoggerManager
from core.utils.chrome_finder import ChromeFinder
from core.proxy.proxy_manager import ProxyManager

class ChromeManager:
    """Chrome浏览器管理器"""
    
    def __init__(self, data_dir: str = "./data"):
        self.logger = LoggerManager.get_logger("chrome_manager")
        self.chrome_finder = ChromeFinder()
        self.data_dir = data_dir
        self.browsers_file = os.path.join(data_dir, "browsers.json")
        self.proxy_manager = ProxyManager()
        # 确保数据目录存在
        os.makedirs(data_dir, exist_ok=True)
        
        # 初始化浏览器列表文件
        if not os.path.exists(self.browsers_file):
            self._save_browsers({})
    
    def _save_browsers(self, browsers: Dict[str, Dict[str, Any]]):
        """保存浏览器列表到文件"""
        try:
            with open(self.browsers_file, 'w', encoding='utf-8') as f:
                json.dump(browsers, f, indent=2, ensure_ascii=False)
        except Exception as e:
            self.logger.error(f"保存浏览器列表失败: {str(e)}")
    
    def _load_browsers(self) -> Dict[str, Dict[str, Any]]:
        """从文件加载浏览器列表"""
        try:
            if os.path.exists(self.browsers_file):
                with open(self.browsers_file, 'r', encoding='utf-8') as f:
                    return json.load(f)
        except Exception as e:
            self.logger.error(f"加载浏览器列表失败: {str(e)}")
        return {}
    
    def _find_available_debug_port(self) -> int:
        """查找可用的调试端口"""
        browsers = self._load_browsers()
        used_ports = set()
        
        # 从已保存的浏览器中获取使用的端口
        for browser_data in browsers.values():
            used_ports.add(browser_data.get('debug_port', 0))
        
  
        # 找到第一个可用端口
        for port in range(9222, 9300):
            if port not in used_ports:
                return port
        
        return 9222
    
    def _build_chrome_cmd(self, chrome_path: str, debug_port: int, user_data_dir: str, proxy_config: Dict[str, str] = None, headless: bool = False) -> list:
        """构建Chrome启动命令行参数"""
        # user_data_dir='C:\data'
        cmd = [
            chrome_path,
            f"--remote-debugging-port={debug_port}",
            f"--user-data-dir={user_data_dir}",
            "--no-first-run",
            "--no-default-browser-check",
            "--start-maximized",
            # "--disable-blink-features=AutomationControlled",
            # "--disable-web-security",
            # "--disable-features=VizDisplayCompositor"
        ]
        # 添加代理参数

        if proxy_config:
            proxy_server = proxy_config.get('server')
            if proxy_server:
                # 添加代理认证参数
                proxy_username = proxy_config.get('username')
                proxy_password = proxy_config.get('password')
                
                self.local_proxy_port = self.proxy_manager.create_local_proxy(
                    proxy_server,
                    proxy_username,
                    proxy_password
                )
                time.sleep(5)
                #修改代理设置为本地代理
                cmd.append(f"--proxy-server=http://127.0.0.1:{self.local_proxy_port}")
                # cmd.append(f"--proxy-server=http://127.0.0.1:8889")
                
                self.logger.info("使用代理认证")

        # 添加无头模式参数
        if headless:
            cmd.append("--headless")
        return cmd

    def _launch_and_register_browser(self, browser_id: str, debug_port: int, user_data_dir: str, cmd: list, proxy_config: Dict[str, str] = None) -> str:
        """启动Chrome进程并注册到管理器，成功返回browser_id，失败返回空字符串"""
        try:
            self.logger.info(f"启动Chrome命令: {' '.join(cmd)}")
            process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0
            )
            time.sleep(10)
            ws_endpoint = None
            try:
                response = requests.get(f"http://localhost:{debug_port}/json", timeout=2)
                if response.status_code == 200:
                    tabs = response.json()
                    if tabs:
                        ws_endpoint = tabs[0].get("webSocketDebuggerUrl")
            except:
                pass

            browser_data = {
                "id": browser_id,
                "debug_port": debug_port,
                "user_data_dir": user_data_dir,
                "status": "running" if ws_endpoint else "failed",
                "ws_endpoint": ws_endpoint,
                "proxy_config": proxy_config or {},
                "process_id": process.pid,
                "created_at": time.time(),
                "cmd": cmd
            }

            browsers = self._load_browsers()
            browsers[browser_id] = browser_data
            self._save_browsers(browsers)

            if browser_data["status"] == "running":
                self.logger.info(f"浏览器创建成功: {browser_id}, 端口: {debug_port}")
                return browser_id
            else:
                self.logger.error(f"浏览器启动失败: {browser_id}")
                return ""
        except Exception as e:
            self.logger.error(f"启动并注册浏览器失败: {str(e)}")
            return ""

    def create_browser(self, proxy_config: Dict[str, str] = None, headless: bool = False) -> str:
        """创建新的浏览器实例"""
        try:
            browser_id = str(uuid.uuid4())
            debug_port = self._find_available_debug_port()
            user_data_dir = os.path.abspath(os.path.join(self.data_dir, "chrome_profiles", browser_id))
            os.makedirs(user_data_dir, exist_ok=True)
            chrome_path = self.chrome_finder.find_chrome_path()
            if not chrome_path:
                raise Exception("未找到Chrome浏览器")
            cmd = self._build_chrome_cmd(chrome_path, debug_port, user_data_dir, proxy_config, headless)
            return self._launch_and_register_browser(browser_id, debug_port, user_data_dir, cmd, proxy_config)
        except Exception as e:
            self.logger.error(f"创建浏览器失败: {str(e)}")
            return ""

    def open_browser(self, browser_id: str,  proxy_config: Dict[str, str] = None, headless: bool = False) -> str:
        """
        打开现有的浏览器（假定已在本地运行），并注册到管理器
        :param browser_id: 浏览器ID
        :param debug_port: 调试端口
        :param proxy_config: 代理配置
        :param headless: 是否无头
        :return: browser_id（成功）或""（失败）
        """
        try:
            # 获取用户数据目录
            user_data_dir = os.path.abspath(os.path.join(self.data_dir, "chrome_profiles", browser_id))
            os.makedirs(user_data_dir, exist_ok=True)
            chrome_path = self.chrome_finder.find_chrome_path()
            if not chrome_path:
                raise Exception("未找到Chrome浏览器")
            # 从已保存的浏览器信息中获取 debug_port
            browser_detail = self.get_browser_detail(browser_id)
            if not browser_detail or "debug_port" not in browser_detail:
                raise Exception("未找到浏览器调试端口(debug_port)")
            debug_port = browser_detail["debug_port"]
            cmd = self._build_chrome_cmd(chrome_path, debug_port, user_data_dir, proxy_config, headless)
            return self._launch_and_register_browser(browser_id, debug_port, user_data_dir, cmd, proxy_config)
        except Exception as e:
            self.logger.error(f"接管现有浏览器失败: {str(e)}")
            return ""


    def delete_browser(self, browser_id: str) -> bool:
        """删除浏览器实例"""
        try:
            browsers = self._load_browsers()
            if browser_id not in browsers:
                self.logger.warning(f"浏览器不存在: {browser_id}")
                return False
            
            browser_data = browsers[browser_id]
            
            # 停止Chrome进程
            if browser_data.get('status') == 'running':
                self._stop_browser_process(browser_data)
            
            # 删除用户数据目录
            user_data_dir = browser_data.get('user_data_dir')
            if user_data_dir and os.path.exists(user_data_dir):
                import shutil
                shutil.rmtree(user_data_dir, ignore_errors=True)
            
            # 从列表中删除
            del browsers[browser_id]
            self._save_browsers(browsers)
            
            self.logger.info(f"浏览器已删除: {browser_id}")
            return True
            
        except Exception as e:
            self.logger.error(f"删除浏览器失败: {str(e)}")
            return False
    
    def _stop_browser_process(self, browser_data: Dict[str, Any]):
        """停止浏览器进程"""
        try:
            process_id = browser_data.get('process_id')
            user_data_dir = browser_data.get('user_data_dir')
            
            # 终止主进程
            if process_id:
                try:
                    process = psutil.Process(process_id)
                    process.terminate()
                    process.wait(timeout=10)
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    pass
            
            # 终止所有相关进程
            for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
                try:
                    if proc.info['name'] and 'chrome' in proc.info['name'].lower():
                        cmdline = proc.info['cmdline']
                        if cmdline and user_data_dir and any(f'--user-data-dir={user_data_dir}' in arg for arg in cmdline):
                            proc.terminate()
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    continue
                    
        except Exception as e:
            self.logger.error(f"停止浏览器进程失败: {str(e)}")
    
    def get_browser_status(self, browser_id: str) -> str:
        """获取浏览器状态"""
        try:
            browsers = self._load_browsers()
            if browser_id not in browsers:
                return "not_found"
            
            browser_data = browsers[browser_id]
            
            # 检查进程是否还在运行
            try:
                process_id = browser_data.get('process_id')
                if process_id:
                    process = psutil.Process(process_id)
                    if process.is_running():
                        # 检查调试端口是否可访问
                        debug_port = browser_data.get('debug_port')
                        try:
                            response = requests.get(f"http://localhost:{debug_port}/json", timeout=2)
                            if response.status_code == 200:
                                return "running"
                        except:
                            pass
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                pass
            
            return "stopped"
            
        except Exception as e:
            self.logger.error(f"获取浏览器状态失败: {str(e)}")
            return "error"
    
    def get_browser_list(self) -> List[Dict[str, Any]]:
        """获取所有浏览器列表"""
        try:
            browsers = self._load_browsers()
            browser_list = []
            
            for browser_id, browser_data in browsers.items():
                # 更新状态
                current_status = self.get_browser_status(browser_id)
                browser_data['status'] = current_status
                
              
                browser_list.append(browser_data)
            
       
            
            return browser_list
            
        except Exception as e:
            self.logger.error(f"获取浏览器列表失败: {str(e)}")
            return []
    
    def get_browser_detail(self, browser_id: str) -> Optional[Dict[str, Any]]:
        """获取浏览器详细信息"""
        try:
            browsers = self._load_browsers()
            if browser_id not in browsers:
                return None
            
            browser_data = browsers[browser_id].copy()
            
            # 更新状态
            current_status = self.get_browser_status(browser_id)
            browser_data['status'] = current_status
           
            
            return browser_data
            
        except Exception as e:
            self.logger.error(f"获取浏览器详情失败: {str(e)}")
            return None


# 全局Chrome管理器实例
chrome_manager = ChromeManager()


def get_chrome_manager() -> ChromeManager:
    """获取Chrome管理器实例"""
    return chrome_manager